package com.wang.gulimall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.common.to.SkuReductionTo;
import com.wang.common.to.SpuBoundTo;
import com.wang.common.utils.PageUtils;
import com.wang.common.utils.Query;
import com.wang.common.utils.R;
import com.wang.gulimall.product.dao.SpuInfoDao;
import com.wang.gulimall.product.entity.*;
import com.wang.gulimall.product.feign.CouponFeignService;
import com.wang.gulimall.product.service.*;
import com.wang.gulimall.product.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("spuInfoService")
@Slf4j
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private AttrService attrService;

    @Autowired
    private SpuInfoDescService spuInfoDescService;

    @Autowired
    private SpuImagesService spuImagesService;

    @Autowired
    private ProductAttrValueService productAttrValueService;

    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SkuImagesService skuImagesServicel;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private CouponFeignService couponFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 商品上架
     * @param spuSaveVo
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveDetail(SpuSaveVo spuSaveVo) {
        //1,保存spu基本信息 pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVo, spuInfoEntity);
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        this.insertSpuInfo(spuInfoEntity);

        //2，保存spu的图片描述 pms_spu_info_desc spu信息介绍
        List<String> decript = spuSaveVo.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        //这里的ID使用的是 新增spuInfoEntity后返回的id
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        //将列表decript中的每一个元素直接加上，返回成一个字符串
        spuInfoDescEntity.setDecript(String.join(",", decript));
        spuInfoDescService.insertSpuInfoDesc(spuInfoDescEntity);

        //3，保存spu的图片集 pms_spu_images
        List<String> images = spuSaveVo.getImages();
        spuImagesService.insertSpuImagesEntity(spuInfoEntity.getId(), images);

        //4，保存spu的规格参数 pms_product_attr_value
        List<BaseAttrs> baseAttrs = spuSaveVo.getBaseAttrs();
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity attrValueEntity = new ProductAttrValueEntity();
            attrValueEntity.setAttrId(attr.getAttrId());
            //需要去属性表中根据id查属性名字
            attrValueEntity.setAttrName(attrService.getById(attr.getAttrId()).getAttrName());
            attrValueEntity.setAttrValue(attr.getAttrValues());
            attrValueEntity.setQuickShow(attr.getShowDesc());
            attrValueEntity.setSpuId(spuInfoEntity.getId());
            return attrValueEntity;
        }).collect(Collectors.toList());
        productAttrValueService.insertProductAttrValues(collect);

        //5，保存spu的积分信息 gulimall_sms -> sms_spu_bounds
        Bounds bounds = spuSaveVo.getBounds();
        SpuBoundTo boundTo = new SpuBoundTo();
        BeanUtils.copyProperties(bounds, boundTo);
        boundTo.setSpuId(spuInfoEntity.getId());
        R boundsRes = couponFeignService.saveSpuBounds(boundTo);
        if ((int) boundsRes.get("code") != 0) {
            log.error("保存spu的积分信息远程服务调用异常");
        }

        //5，保存spu对应的所有sku信息
        //5.1 保存sku基本信息 pms_sku_info
        List<Skus> skus = spuSaveVo.getSkus();
        //非空判断
        if (skus != null && skus.size() > 0) {
            /**
             * 这里解释一下，为什么不用流式编程而使用foreach循环
             * 因为下面所有的与sku有关的保存都需要关联sku的id，
             * 使用流式编程的话，保存后无法获取数据库id字段自增后的id值，除非进行beanutils中的属性对拷，那就有点麻烦了（这里解释错错了）
             * 是这样的，是用流式编程最终会收集成一个skuInfoEntity的list，然后经行批量保存，
             * 但是进行批量保存的话就无法获取每一个skuinfo的自增id，而后续的与sku有关的信息保存都会使用sku的id
             * 所以无法使用流式编程，只能一个一个的保存，这样才能获取保存后数据库设置的自增id
             * 使用foreach循环的话，每一项执行save后，mybatis都会把自增后的id，set到实体类中！
             */
            skus.forEach(item -> {
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                BeanUtils.copyProperties(item, skuInfoEntity);
                //品牌id与spu相同
                skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
                //三级分类也一样
                skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
                //销量默认0
                skuInfoEntity.setSaleCount(0L);
                //与spuid关联
                skuInfoEntity.setSpuId(spuInfoEntity.getId());
                //设置默认图片 图片在vo中的Images，又因为图片信息也要保存，所以这里直接处理了
                //但遇到一个问题，这里提前处理没法得到保存后的skuid，所以寻找默认图片还是得提前整
                List<Images> imagesList = item.getImages();
                String defaultImg = "";
                /**
                 * todo
                 * 这里如果使用lambda表达式的foreach循环会报如下错误
                 * Variable used in lambda expression should be final or effectively final
                 * imagesList.forEach(img -> {
                 *     if (img.getDefaultImg() == 1){
                 *         defaultImg = img.getImgUrl();
                 *     }
                 * });
                 */
                for (Images img : imagesList) {
                    if (img.getDefaultImg() == 1) {
                        defaultImg = img.getImgUrl();
                    }
                }
                skuInfoEntity.setSkuDefaultImg(defaultImg);
                //至此，skuInfo设置完毕，开始保存
                skuInfoService.insertSkuInfo(skuInfoEntity);
                //保存成功后，mybatisplus会将数据库自增后得到的skuid设置到skuInfoEntity中
                Long skuId = skuInfoEntity.getSkuId();

                //5.2 保存sku的图片信息 pms_sku_images
                List<SkuImagesEntity> imagesEntities = imagesList.stream().map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                })
                        //加上filter过滤无意义数据 filter返回ture，就留下，返回false就剔除
                        .filter(img -> StringUtils.isNotEmpty(img.getImgUrl()))
                        .collect(Collectors.toList());
                //todo (已解决)没有图片路径的无需保存DEBUG时发现
                //向pms_sku_images保存sku的图片信息
                skuImagesServicel.insertSkuImages(imagesEntities);

                //5.3 保存sku的销售属性信息 pms_sku_sale_attr_value
                List<Attr> attrs = item.getAttr();
                List<SkuSaleAttrValueEntity> saleAttrValueEntities = attrs.stream().map(attr -> {
                    SkuSaleAttrValueEntity valueEntity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(attr, valueEntity);
                    valueEntity.setSkuId(skuId);
                    return valueEntity;
                }).collect(Collectors.toList());
                //开始保存
                skuSaleAttrValueService.insertSkuSaleAttrValue(saleAttrValueEntities);

                //5.4 保存sku的优惠、满减等信息
                // 这个涉及其他的数据库 gulimall_sms
                // sms_sku_ladder:几件打几折
                // sms_sku_full_reduction：满减信息，满几件打几折
                // sms_member_price：商品不同会员登记对应的价格
                SkuReductionTo skuReductionTo = new SkuReductionTo();
                BeanUtils.copyProperties(item, skuReductionTo);
                skuReductionTo.setSkuId(skuId);
                //调用其他服务时，需要对数据经行筛选，如果无意义那就不用保存
                if (skuReductionTo.getFullCount()>0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1){

                }
                R reductionRes = couponFeignService.saveSkuReduction(skuReductionTo);
                if ((int) reductionRes.get("code") != 0) {
                    log.error("保存sku的优惠、满减等信息远程服务调用异常");
                }

            });
        }

    }

    /**
     * 向pms_spu_info表中新增一条数据
     * @param spuInfoEntity
     */
    @Override
    public void insertSpuInfo(SpuInfoEntity spuInfoEntity) {
        baseMapper.insert(spuInfoEntity);
    }


}